Je ne sais pas vous mais, parfois, quand je commence un projet, certains éléments m'apparaissent comme une évidence des le départ.
Quand j'ai rejoins l'équipe de Codecarbon et qu'on m'a demandé de réflechir à un nouveau dashboard, j'ai su que je voulais faire cet élément :

C'est à dire une série de doughnut charts qui me serviraient de support pour afficher le poids d'un projet particulier dans l'organisation et qui reprennaient le thème du logo CodeCarbon :
Cette idée en apparence simple m'a posé quelques défis de réalisation.
Alors comment customiser un 'camembert' avec plotly ? c'est parti
Ici je ne vais utiliser que les graph_objects car c'est la méthode la plus flexible pour customiser des graphiques
import pandas as pd
import plotly.graph_objects as go
J'ai téléchargé une partie des données en base sur le projets Codecarbon sous forme de csv pour les besoins des tests. Donc ce n'est pas exactement ce que l'on a quand on utlise Codecarbon en local sur son ordi, ne soyez pas surpris.
import pandas as pd
df=pd.read_csv('new_emissions_df.csv')
df[:3]
| Unnamed: 0 | timestamp | run_id | duration | emissions_sum | energy_consumed | experiment_id | experiment_name | experiment_description | country_name | ... | region | on_cloud | cloud_provider | cloud_region | project_id | project_name | project_description | team_id | name | description | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 2021-07-04T06:36:04.747877 | 9780b248-7c75-48c0-9f36-2f9221e798a5 | 23 | 0.000266 | 0.000627 | 5b0fa12a-3dd7-45bb-9766-cc326314d9f1 | Code Carbon user test | Code Carbon user test with default project | France | ... | france | False | NaN | NaN | e60afa92-17b7-4720-91a0-1ae91e409ba1 | Default Project | Default Project Code Carbon DataForGood Team | 8edb03e1-9a28-452a-9c93-a3b6560136d7 | DataForGood | DataForGood Team |
| 1 | 1 | 2021-07-04T06:43:40.847861 | 95ae3555-a329-4a1f-b3b4-64f2e89b5fcc | 122 | 0.002314 | 0.005451 | 5b0fa12a-3dd7-45bb-9766-cc326314d9f1 | Code Carbon user test | Code Carbon user test with default project | France | ... | france | False | NaN | NaN | e60afa92-17b7-4720-91a0-1ae91e409ba1 | Default Project | Default Project Code Carbon DataForGood Team | 8edb03e1-9a28-452a-9c93-a3b6560136d7 | DataForGood | DataForGood Team |
| 2 | 2 | 2021-07-04T06:45:17.688324 | 95ae3555-a329-4a1f-b3b4-64f2e89b5fcc | 96 | 0.001747 | 0.004116 | 5b0fa12a-3dd7-45bb-9766-cc326314d9f1 | Code Carbon user test | Code Carbon user test with default project | France | ... | france | False | NaN | NaN | e60afa92-17b7-4720-91a0-1ae91e409ba1 | Default Project | Default Project Code Carbon DataForGood Team | 8edb03e1-9a28-452a-9c93-a3b6560136d7 | DataForGood | DataForGood Team |
3 rows × 21 columns
De manière arbitraire, je choisis ici de travailler sur le premier projet de la liste. Dans le dashbord évidemment, on peut choisir son projet.
project_emissions = df[df['project_name']==df.project_name.unique()[0]]['emissions_sum'].sum()
La figure de base du pie chart avec plotly est très simple. Elle n'a besoin que d'une liste de valeurs.
Ici values va recevoir une liste contenant les emissions émises par le projet et la difference entre le total des émissions émises par l'organisation et les émissions émises par le projet.
Comme je ne luis ai pas spécifier de nom pour les éléments de la liste, plotly va les nommer selon leur position dans la liste.
fig = go.Figure([go.Pie(values= [project_emissions,df.emissions_sum.sum()-project_emissions])])
fig.show()
L'une des principales force de plotly est de faire des graph interactifs.
On a donc ici un hover et des label qui s'affiche pour indiquer le pourcentage représenté par chacune des catégories.
Ici cependant je n'en veux pas donc j'applique textinfo = 'none' pour supprimer les labels et hoverinfo='skip pour supprimer les infobulles
fig = go.Figure([go.Pie(values= [project_emissions,df.emissions_sum.sum()-project_emissions],
textinfo='none', #supprime les labels
hoverinfo='skip', #supprime l'infobulle
)])
fig.show()
Ensuite je vais dessiner un joli trou dans mon pie chart et ajouter un titre au centre
fig = go.Figure([go.Pie(values= [project_emissions,df.emissions_sum.sum()-project_emissions],
textinfo='none',
hoverinfo='skip',
hole=.7, #dessine un trou
title=str(round(project_emissions)) + ' Kg eq. CO2' #ajoute un titre au centre
)])
fig.show()
On va appliquer les couleurs du thème.
Vous noterez que marker reçoit un dictionnaire contenant les couleurs que je souhaite utilisé. Je trouve que ce n'est pas toujours facile de savoir comment sont
rangés les différents éléments qui le composent marker alors voici un lien vers la documentation https://plotly.com/python/marker-style/
darkgreen = '#024758'
vividgreen ='#c9fb37'
greygreen = '#226a7a'
fig = go.Figure([go.Pie(values= [project_emissions,df.emissions_sum.sum()-project_emissions],
textinfo='none',
hoverinfo='skip',
hole=.8,
title=str(round(project_emissions)) + ' Kg eq. CO2',
marker=dict(colors=[vividgreen, greygreen]
))])
fig.update_layout(
font=dict(color='white'),paper_bgcolor=darkgreen,
height=400,
showlegend=False, #supprime la légende
)
fig.show()
Jusqu'ici, tout va bien.
L'un des problèmes que j'ai rencontré est sur le titre. Il est un peu perdu au milieu de son grand cercle.
Je ne voulais pas non plus que la valeur soit au même niveau d'importance que l'unité !
Malheur! dans ce cas précis go.figure n'accepte pas le css inline !
il a fallu ruser!
J'ai gardé le titre pour les unités et je l'ai positionné en bas de mon graphique et j'ai utilisé les annotations pour rentrer la valeur!
tada!
fig = go.Figure([go.Pie(values= [project_emissions,df.emissions_sum.sum()-project_emissions],textinfo='none',
hoverinfo='skip', hole=.8,
title= ' Kg eq. CO2', # on garde le titre pour les unités
title_position='bottom center',# on le place en dessous du graph
title_font=dict(size=20),# on choisi sa taille
marker=dict(colors=[vividgreen, greygreen]))])
fig.update_layout(font=dict(color='white'),paper_bgcolor=darkgreen,showlegend=False, height=400,
annotations= [dict(text=str(round(project_emissions)), x=0.51, y=0.44,# on corrige la supperposition
font=dict(size=60))] # annotations va toujours dans une liste
)
fig.show()
Comme vous le voyez sur le dashboard, j'ai 3 pieCharts à la suite. Naturellement, je me suis dit que j'allais placé chaque graphique dans un dbc.card et bien le résultat est très très vilain!
Donc encore une fois j'ai dû ruser et utiliser subplot
# construisons quelques aggrégat
project_energy = df[df['project_name']==df.project_name.unique()[0]]['energy_consumed'].sum()
duration = df[df['project_name']==df.project_name.unique()[0]]['duration'].sum()
#pour modifier l'unité de durée en fonction de la valeur
duration_project = str(round(duration,))
duration_project_unit = 'min'
if duration >= 60:
duration_in_hours=duration/60
duration_project="{:.0f}".format(duration_in_hours)
duration_project_unit = 'H'
if duration_in_hours >= 24:
duration_in_days=duration_in_hours/24
duration_in_years="{:.0f}".format(duration_in_days)
duration_project_unit='days'
if duration_in_days>=365:
duration_in_years = duration_in_days/365
duration_project='{:.0f}'.format(duration_in_years)
duration_project_unit='year'
from plotly.subplots import make_subplots #ne pas oublier d'importer la librairieb
figPie = make_subplots(rows=1, cols=3, # on spécifie les caractéristique du subplot le nombre de rang et de colonnes
specs=[[{'type': 'domain'}, {'type': 'domain'}, {'type': 'domain'}]])
figPie.add_trace(go.Pie(values=[project_energy, df.energy_consumed.sum()-project_energy], title="KwH",title_position='bottom center', textinfo='none', hole=.8, marker=dict(colors=[vividgreen, greygreen]), hoverinfo='skip'),
row=1, col=1) # on donne la postion du plot
figPie.add_trace(go.Pie(values=[project_emissions, df.emissions_sum.sum()-project_emissions], textinfo='none', hole=.8, marker=dict(colors=[vividgreen, greygreen]), hoverinfo='skip', title='Kg eq.CO2', title_position='bottom center'), row=1, col=2)
figPie.add_trace(go.Pie(values=[duration, (df.duration.sum()-duration)], textinfo='none', hole=.8, marker=dict(colors=[vividgreen, greygreen]), hoverinfo="skip", title=duration_project_unit,title_position='bottom center'), row=1, col=3)
figPie.update_layout(font=dict(color='white'), paper_bgcolor=darkgreen,height=400,showlegend=False,
annotations=[dict(text=str(round(project_energy)), font=dict(color='white',), x=0.09, y=0.5, font_size=50, showarrow=False), #chaque dictionnaire va correspondre à un graphique
dict(text=str(round(project_emissions)), x=0.5,
y=0.5, font_size=50, showarrow=False),
dict(text=duration_project, font=dict(color='white',),
x=0.885, y=0.5, font_size=50, showarrow=False) #il faut positionner l'annotation par les coordonnées x et y
],
margin=dict(l=10, r=10, b=10, t=10))
Si vous êtes parvenus jusqu'ici BRAVO et merci.
J'espère que ce petit guide pas à pas vous a été utile et qu'il vous a donner des idées pour personnaliser vos graphiques.
Data for good en général et code Carbon en particulier sont toujours à la recherche de bénévoles pour les aider sur leur projet alors si vous êtes intéressés n'hésitez pas à vous présenter sur le slack !
Encore merci d'avoir pris le temps de me lire. Prenez soin de vous!